#!/bin/bash
# commandtodnp driver


############################################
###### DO NOT MODIFY PARAMETERS BELOW ######
############################################
SVN_ID='$Id: commandtodnp 676 2009-03-17 22:30:56Z tyler $'
svn_vers=${SVN_ID#$'\x24Id: commandtodnp '};svn_vers=${svn_vers%% *}
PATH=$PATH:/usr/bin:/bin:/usr/sbin:/sbin
############################################
####### START OF FUNCTION DEFINITIONS ######
############################################
function cleanupOnExit ()
{
  db "cleaning up."
  local -i code=${1:-$?}
#rm -rf "${tmp_dir}"
  if ((0 == g_got_SIGPIPE));then
   db "Task complete with exit code $code"
   ((code)) && fatal
  fi
  db "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv"
}

function logDate ()
{
    date '+[%Y/%m/%d %H:%M:%S %z]'
}
function db ()
{
    ((g_got_SIGPIPE)) ||
	>&2 echo "DEBUG: commandtodnp: $@"
}
usage () {
  >&2 echo "usage: $0 job-id user title copies options [file]";
  exit 1
}
function info ()
{
    ((g_got_SIGPIPE)) ||
	>&2 echo "INFO: $@"
}
function ppdEmit ()
{
    ((g_got_SIGPIPE)) ||
	>&2 echo "PPD: $@"
}
function cups_Attribute ()
{
    ((g_got_SIGPIPE)) ||
	>&2 echo ATTR: $1="${2}"
}
function dumpViz ()
{
   local line IFS='
'
   local -a multi=($(echo -n "$@" | unvis | hexdump -Cv))
#   unset IFS
   for line in "${multi[@]}" ;do db $line;done
}
function dumpString ()
{
   local line IFS='
'
   local -a multi=($(echo -en "$@" | hexdump -Cv))
   for line in "${multi[@]}" ;do db $line;done
}
stripLeadingZeros ()
{
    local t;
    local v="${1//\\^@}";
    v="${v//\\^M}";
    until test "$t" == "$v"; do
        t=$v;
        v=${v#0};
    done;
    echo $v
}


function updateFromPPD ()
{
  FWName=$(awk '/^[*]PrinterFirmwareVersion/ {if(length($2)){print $2;nextfile}}' ${PPD})
  model=$(awk '/^\*ModelName:/ {m=$NF;sub(/"/,"",m);print m}' ${PPD})
  lastMediaType=$(awk '/^\*PrinterInstalledMedia:/ {print $NF}' ${PPD})
  lastMediaClass=$(awk '/^\*PrinterInstalledMediaClass:/ {print $NF}' ${PPD})
  lastMediaQty=$(awk '/^\*MediaRemaining:/ {print $NF}' ${PPD})
  ((03 == lastMediaClass)) && mediaClass="PP Media" || mediaClass="SD Media"
  db "Model=$model"
  db "ModelFW=$FWName"
  db "lastUsedMedia=$lastMediaType"
  db "lastUsedMediaClass=$lastMediaClass"
  db "lastMediaQTY=$lastMediaQty"
}

infoForMediaType ()
{
  local mClass=" ${mediaClass}"
    case ${1} in
#DS40
    00201|00200)
      mediaMax=400
      mediaName="5x3.5"
      ((media -= 50))
      ;;
    00210|00211)
      mediaMax=200
      mediaName="5x7"
      ((media -= 50))
      ;;
    00301|00300)
      mediaMax=400
      mediaName="6x4"
      ((media -= 50))
      ;;
    00310|00311)
      mediaMax=200
      mediaName="6x8"
      ((media -= 50))
      ;;
    00400|00401)
      mediaMax=180
      mediaName="6x9"
      ((media -= 50))
      ;;
#DS40
    DS40-00200|DS40-00201)
      mediaMax=400
      mediaName="DS40 5x3.5"
      ((media -= 50))
      ;;
    DS40-00210|DS40-00211)
      mediaMax=200
      mediaName="DS40 5x7"
      ((media -= 50))
      ;;
    DS40-00300|DS40-00301)
      mediaMax=400
      mediaName="DS40 6x4"
      ((media -= 50))
      ;;
    DS40-00310|DS40-00311)
      mediaMax=200
      mediaName="DS40 6x8"
      ((media -= 50))
      ;;
    DS40-00400|DS40-00401)
      mediaMax=180
      mediaName="DS40 6x9"
      ((media -= 50))
      ;;
# DS620
    DP-DS620-00200|DP-DS620-00201)
      mediaMax=400
      mediaName="DS620 5x3.5"
      ((media -= 0))
      ;;
    DP-DS620-00210|DP-DS620-00211)
      mediaMax=230
      mediaName="DS620 5x7"
      ((media -= 0))
      ;;
    DP-DS620-00300|DP-DS620-00301)
      mediaMax=400
      mediaName="DS620 6x4"
      ((media -= 0))
      ;;
    DP-DS620-00310|DP-DS620-00311)
      mediaMax=200
      mediaName="DS620 6x8"
      ((media -= 0))
      ;;
    DP-DS620-00400|DP-DS620-00401)
      mediaMax=180
      mediaName="DS620 6x9"
      ((media -= 0))
      ;;
# DS820
    DP-DS820-00500|DP-DS820-00501)
      mediaMax=130
      mediaName="DS820 8x10"
      ((media -= 0))
      ;;
    DP-DS820-00510|DP-DS820-00511)
      mediaMax=110
      mediaName="DS820 8x12"
      ((media -= 0))
      ;;
    DP-DS820-00600|DP-DS820-00601)
      mediaMax=110
      mediaName="DS820 A4"
      ((media -= 0))
      ;;
#RX-1
    DS-RX1-00301|DS-RX1-00300)
      mediaMax=700
      mediaName="RX1 6x4"
      ((media -= 50))
      ;;
    DS-RX1-00210|DS-RX1-00211)
      mediaMax=400
      mediaName="RX1 5x7"
      ((media -= 50))
      ;;
    DS-RX1-00310|DS-RX1-00311)
      mediaMax=350
      mediaName="RX1 6x8"
      ((media -= 50))
      ;;
#DS80
    DS80-00500|DP-DS80D-00500|0500|500|00500|00501|DS80-00501|DP-DS80D-00501)
      mediaMax=130
      mediaName="8x10"
      ((media -= 50))
      ;;
    DS80-00510|DP-DS80D-00510|0510|510|00510|00511|DS80-00511|DP-DS80D-00511)
      mediaMax=110
      mediaName="8x12"
      ((media -= 50))
      ;;
    default|*)
      mediaMax=0
      mediaName="No Media"
      mClass=
      ;;
  esac
  ((0 > media)) && media=0

  #special case for DS620A (to add the "A")
  test DS620A = "${FWName}" && mediaName=${mediaName/DS620/DS620A}

  # add media class
  test DS820 = "${FWName}" && mediaName="${mediaName}$mClass"
  #special case for DS820A (to add the "A")
  test DS820A = "${FWName}" && mediaName="${mediaName/DS820/DS820A}$mClass"
}

###################################################################################
# DNP USB status functions follow
###################################################################################

function  dnp_getUSBReply ()
{
  # pass any argument to this function to suppress the logging of reply
   local noDump=$1
   local i=0
   # read CUPS backchannel data on fd3
   # reply size is the first 8 bytes in UTF8 decimal digits
   local header
    header="$(2>/dev/null <&3 dd bs=8 count=1|vis)";
   until test "$header";do
    ((11 == i)) && { db "failed to read reply";return; }
    sleep $((++i))
    header="$(2>/dev/null <&3 dd bs=8 count=1|vis)";
   done
   test "$noDump" || dumpViz "${header}"
   local -i size=$(stripLeadingZeros "${header}" )
   if ((0 < size));then
     db "reading $size bytes from backchannel"
     response="$(2>/dev/null <&3 dd bs=$((size)) count=1|vis)" &&
      test "$noDump" || dumpViz "$response"
     response="${response//\\^@/}"
     response="${response//\\^M/}"
     response="${response//\\000/}"
   fi
}
#commands are at least 32 bytes and unused bytes are ' ' "space" chars (i.e. 0x20)
function dnp_GetFirmwareVersion ()
{
# send the get firmware command and read a reply
cmd='\x1bPINFO  FVER                    '
db "Sending GetPrinterVersion command"
echo -en "${cmd}"
}
function dnp_GetSerialNumber ()
{
# send the get firmware command and read a reply
cmd='\x1bPINFO  SERIAL_NUMBER           '
db "Sending GetSerialNumber command"
echo -en "${cmd}"
}

function dnp_GetPrinterStatus ()
{
# send the get status command and read a reply
cmd='\x1bPSTATUS                        '
db "Sending GetPrinterStatus command"
echo -en "${cmd}"
}

function dnp_GetUSBSerialNumberStatus ()
{
# send the get status command and read a reply
cmd='\x1bPMNT_RDUSB_ISERI_SET   ''        '
db "Sending GetiSerialNumberStatus command"
echo -en "${cmd}"
}

function dnp_USBSerialNumberEnable ()
{
# send the get status command and read a reply
cmd='\x1bPMNT_WTUSB_ISERI_SET   ''00000004''01\xd\x0'
db "Sending SetiSerialNumberStatus ENABLE command"
echo -en "${cmd}"
}

function dnp_USBSerialNumberDisable ()
{
# send the get status command and read a reply
cmd='\x1bPMNT_WTUSB_ISERI_SET   ''00000004''00\xd\x0'
db "Sending SetiSerialNumberStatus DISABLE command"
echo -en "${cmd}"
}

function dnp_GetDuplexStatus ()
{
# send the get duplex status command and read a reply
cmd='\x1bPINFO  UNIT_STATUS             '
db "Sending GetDuplexStatus command"
db $(dumpString "$cmd")
echo -en "${cmd}"
}

function dnp_GetMedia ()
{
# send the get media command and read a reply
cmd='\x1bPINFO  MEDIA                   '
db "Sending GetMedia command"
db $(dumpString "$cmd")
echo -en "${cmd}"
}
function dnp_GetMediaClass () {
# send the get media command and read a reply
cmd='\x1bPINFO  MEDIA_CLASS_RFID        '
db "Sending GetMediaClass command"
db $(dumpString "$cmd")
echo -en "${cmd}"
}

function dnp_GetCutMedia ()
{
# send the get media command and read a reply
cmd='\x1bPINFO  UNIT_CUT_PAPER               '
db "Sending getCutPaper command"
db $(dumpString "$cmd")
echo -en "${cmd}"
}

function dnp_ReadDuplexCounter ()
{
# send the Read Duplex Counter command and read a reply
cmd='\x1bPMNT_RDCOUNTER_DUPLEX          '
db "Sending ReadDuplexCounter command"
db $(dumpString "$cmd")
echo -en "${cmd}"
}

function dnp_GetDuplexVersion ()
{
# send the get media command and read a reply
cmd='\x1bPINFO  UNIT_FVER               '
db "Sending GetDuplexVersion command"
db $(dumpString "$cmd")
echo -en "${cmd}"
}

function dnp_GetFreeBuffers ()
{
# send the get free buffers command and read a reply
cmd='\x1bPINFO  FREE_PBUFFER            '
db "Sending GetFreeBuffers command"
db $(dumpString "$cmd")
echo -en "${cmd}"
}

function dnp_GetPrintsRemaining ()
{
# send the get prints remaining command and read a reply
cmd='\x1bPINFO  MQTY                    '
db "Sending GetPrintsRemaining command"
db $(dumpString "$cmd")
echo -en "${cmd}"
}

function dnp_DuplexCancel ()
{
# send the duplex_cancel command and read a reply
cmd='\x1bPCNTRL DUPLEX_CANCEL           '
db "Sending DuplexCancel command"
db $(dumpString "$cmd")
echo -en "${cmd}"
}

function  dnp_getInstalledMedia ()
{
    dnp_GetMedia
    dnp_getUSBReply

    #response is a string starting 0nnnn\r
    mediaType=${response#MT}
    test "$mediaType" && ppdEmit PrinterInstalledMedia=$mediaType
}
function  dnp_getMediaClass ()
{
    test "${model}" = "DP-DS820" || return
    dnp_GetMediaClass
    dnp_getUSBReply

    #response is a string starting 000n\r
    local mediaClassValue=$(stripLeadingZeros ${response})
    test "$mediaClassValue" && ppdEmit PrinterInstalledMediaClass=$mediaClassValue
    ((03 == mediaClassValue)) && mediaClass="PP Media" || mediaClass="SD Media"

}

function  dnp_GetFirmwareString ()
{
    db "Getting printer firmware version"
    dnp_GetFirmwareVersion
    dnp_getUSBReply

    #response is a string starting 0nnnn\r
    state=${response}
    shopt -s extglob
    state=${state/%*( )}
    test "$state" && ppdEmit PrinterFirmwareVersion="\"${state}"\"
    FWName=$(echo "${state}"|awk '{print $1}')

}
function  dnp_GetSerialNumberString ()
{
    db "Getting printer serial number"
    dnp_GetSerialNumber
    dnp_getUSBReply

    #response is a string starting 0nnnn\r
    state=${response}
    shopt -s extglob
    state=${state/%*( )}
    test "$state" && ppdEmit USBSerialNumber="\"${state}"\"
}

function  dnp_ReportStatus ()
{
    db "Getting printer status"
    dnp_GetPrinterStatus
    dnp_getUSBReply

    #response is a string starting 0nnnn\r
    state=${response}
    test "$state" && ppdEmit PrinterStatus=$state
}

function  dnp_ReportSupplyLevels ()
{
    dnp_GetMedia
    dnp_getUSBReply

    #response is a string starting 0nnnn\r
    mediaType=${response}
    if test "${mediaType}" != "${mediaType#MT}"; then
      mediaType=${mediaType#MT}
      ppdEmit PrinterInstalledMedia=$mediaType
    else
      mediaType=${lastMediaType:-0}
    fi

    dnp_getMediaClass

    dnp_GetPrintsRemaining
    dnp_getUSBReply

    #response is a string starting MQTY0157\r
    MQTY=${response}
    if test "${MQTY}" != "${MQTY#MQTY}"; then
      qty=$(stripLeadingZeros ${MQTY#MQTY})
      ppdEmit MediaRemaining=$qty
    else
      qty=${lastMediaQty:-0}
    fi
    declare -i media=$((${qty:-0}))
    declare -i mediaMax=1
    lookupKey=${model}${model:+-}${mediaType}
    db "Getting info for ${lookupKey}"
    infoForMediaType ${lookupKey}
    declare -i level
    level=-3
    ((0<mediaMax)) && level=$((100*media/mediaMax))
    >&2 echo ATTR: marker-message=\'"$media/$mediaMax"\' marker-colors=#00FFFF marker-levels=$level marker-names=\'"${mediaName}"\' marker-types=inkRibbon
}
function dnp_620Check ()
{
    test "${model}"="DP-DS620" || return
    dnp_GetUSBSerialNumberStatus
    dnp_getUSBReply
    #response is a string starting 0nnnn\r
    state=${response}
    test "$state" && ppdEmit USBSerialNumberStatus=${state:(-1)}
    #((${state:(-1)})) || dnp_USBSerialNumberEnable
    ((1 == state)) && dnp_GetSerialNumberString
}
function  dnp_ReportDuplexStatus ()
{
    db "Getting printer status"
    dnp_GetPrinterStatus
    dnp_getUSBReply
    
    #response is a string starting 0nnnn\r
    state=${response}
    test "$state" && ppdEmit PrinterStatus=$state

    db "Getting duplex unit status"
    dnp_GetDuplexStatus
    dnp_getUSBReply

    #response is a string starting nnnnn\r
    state=${response}
    test "$state" && ppdEmit DuplexUnitStatus=$state

    dnp_GetCutMedia
    dnp_getUSBReply

    #response is a string starting CUTPnnnn\r
    CUTP=${response}
    CUTP=${CUTP#CUTP}
    test "$CUTP" && ppdEmit PrinterCutMedia=$CUTP


    dnp_GetDuplexVersion
    dnp_getUSBReply
    #response is a string starting nnnn\r
    UNIT=${response}
    test "$UNIT" && ppdEmit DuplexUnitVersion=$UNIT

    dnp_ReadDuplexCounter
    dnp_getUSBReply
    #response is a string starting CDUPnnnn\r
    CDUP=${response}
    qty=$(stripLeadingZeros ${CDUP#CDUP})
    test "$qty" && ppdEmit DuplexCounter=$qty
}
############################################
####### END OF FUNCTION DEFINITIONS ########
############################################
# verify correct argc
(($# == 5 || $# == 6)) || usage

trap gotTERM TERM HUP QUIT
trap gotPIPE PIPE
trap cleanupOnExit EXIT

db "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"
db "Starting up ..."

db "PPD=${PPD}"

updateFromPPD

# parse input stream for a supported command and execute

if((6 == $#)); then
db reading from file $6
# redirect file on argv[6] to stdin
  exec <$6
fi

isDuplex=$(test -r "$PPD" && awk '/^[*]cupsCommands/ {if(match($0,/ReportDuplex/))print 1; else print 0}' "$PPD")
while read command arg; do
test "${command:0:1}" = "#" -o -z "${command}" && continue
db "found command ${command}"
case ${command} in

  AutoConfigure)
  #############
    ((isDuplex)) && dnp_ReportDuplexStatus
    dnp_GetFirmwareString
    dnp_ReportSupplyLevels
    dnp_ReportStatus
    dnp_620Check
  ;;

  com.dnpphoto.ReportDuplex)
  ############
    dnp_ReportDuplexStatus
  ;;

  ReportStatus)
  ############
    dnp_ReportStatus
  ;;

  ReportLevels)
  ############
    dnp_GetFirmwareString
    dnp_ReportSupplyLevels
    dnp_620Check
  ;;

  com.dnpphoto.GetSerialNumberStatus)
  ############
    dnp_620Check
  ;;

  PDEUpdate)
  ############
    dnp_GetFirmwareString
# PrinterSupports2InchCut: False
  ;;

  colorMatchingEnable)
  ############
  ppdEmit APSupportsCustomColorMatching=True
  ;;

  colorMatchingDisable)
  ############
  ppdEmit APSupportsCustomColorMatching=False
  ;;

esac
done

# notify that cups will update the PPD
cupsDest=$(basename "${PPD}")
db "notifying for $cupsDest"
notifyutil -p $cupsDest 
###################################################################################

